package com.huwaiwai.lock.mylock;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * Created by hww on 2019/1/8 3:17 PM.
 */
public class MyLock {

    private final MyLock.Sync sync;

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -7620906840861245218L;

        abstract void lock();

        boolean unLock() {
            return tryRelease(1);
        }

        @Override
        protected final boolean tryRelease(int arg) {
            if (getExclusiveOwnerThread() != Thread.currentThread()) {
                throw new Error("错误");
            }
            int newState = getState() - arg;
            if (newState < 0) {
                throw new Error("错误");
            }
            boolean free = false;
            if (newState == 0) {
                setExclusiveOwnerThread(null);
                free = true;
            }
            setState(newState);
            return free;
        }

        int holdCount() {
            return getState();
        }

        void doUpdateCurrentThread(int newState) {
            if (newState < 0) {
                throw new Error("错误");
            }
            setState(newState);
        }

    }

    /** 不公平锁控制器 */
    static final class UnFairSync extends Sync {
        private static final long serialVersionUID = -6950136266231459078L;
        @Override
        protected final boolean tryAcquire(int arg) {
            int state = getState();
            if (state == 0) {
                if (compareAndSetState(state, state + arg)) {
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
            } else if (getExclusiveOwnerThread() == Thread.currentThread()) {
                doUpdateCurrentThread(state + arg);
                return true;
            }
            return false;
        }

        @Override
        void lock() {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
            } else {
                acquire(1);
            }
        }
    }

    /** 公平锁控制器 */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -6092913349025938640L;
        @Override
        protected final boolean tryAcquire(int arg) {
            int state = getState();
            if (state == 0) {
                //公平锁的关键 有其他等待线程 则不请求锁
                if (!hasQueuedPredecessors() && compareAndSetState(state, state + arg)) {
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
            } else if (getExclusiveOwnerThread() == Thread.currentThread()) {
                doUpdateCurrentThread(state + arg);
                return true;
            }
            return false;
        }

        @Override
        void lock() {
            acquire(1);
        }
    }

    /**
     * 加锁
     */
    public void lock() {
        sync.lock();
    }

    /**
     * 解锁
     */
    public boolean unlock() {
        return sync.unLock();
    }

    /**
     * 当前有多少线程占有资源
     */
    public int holdCount() {
        return sync.holdCount();
    }

    public MyLock() {
        this.sync = new FairSync();
    }

    public MyLock(boolean fair) {
        this.sync = fair ? new FairSync() : new UnFairSync();
    }


}
